﻿
// myProjectView.cpp: CmyProjectView 类的实现
//
#include <cstdio>
#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "myProject.h"
#endif

#include "myProjectDoc.h"
#include "myProjectView.h"

// 小组代码声明区开始####################################################
#define N_MAX_POINT 10//控制多边形的最大顶点数

#include "MainFrm.h"

//// 边记录：
//struct CAET
//{//记录边的结构体
//	double      x;//边的x坐标
//	int         yMax;//顶点y坐标最大值
//	double      k;   //边斜率的倒数
//	CAET* next;    //下一条边记录指针
//};
//// 桶记录
//struct CBucket
//{//记录扫描线的结构体
//	int          ScanLine;       //扫描线y坐标
//	CAET* p;                //桶上的边表头指针
//	CBucket* next;  //下一条桶记录指针
//} *HeadB;
//CPoint* pt;//顶点
//CPoint* pt_project;//映射后的顶点
//int CtrlPNum{ 4 };
//CAET* ourAet = nullptr; // 记录所有的边
//bool m_flag;


// 小组代码声明区结束####################################################


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CmyProjectView

IMPLEMENT_DYNCREATE(CmyProjectView, CView)

BEGIN_MESSAGE_MAP(CmyProjectView, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_COMMAND(ID_huitu, &CmyProjectView::OnHuitu)
	ON_WM_LBUTTONDOWN()
	ON_COMMAND(ID_DUOBIANXING, &CmyProjectView::OnDuobianxing)
END_MESSAGE_MAP()

// CmyProjectView 构造/析构

CmyProjectView::CmyProjectView() noexcept
{
	// TODO: 在此处添加构造代码

}

CmyProjectView::~CmyProjectView()
{
}

BOOL CmyProjectView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CmyProjectView 绘图

void CmyProjectView::OnDraw(CDC* pDC)
{
	//CmyProjectDoc* pDoc = GetDocument();
	//ASSERT_VALID(pDoc);
	//if (!pDoc)
	//	return;

	// TODO: 在此处为本机数据添加绘制代码
	CmyProjectDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	CRect rect;
	GetClientRect(&rect);
	pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区:x轴水平向右，y轴垂直向上
	pDC->SetViewportOrg(rect.Width() / 2 - 400, rect.Height() / 2);//坐标系原点，向左平移了400单位
	//绘制坐标轴
	CPen NewPen, * pOldPen;
	NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	pOldPen = pDC->SelectObject(&NewPen);

	int minX = -10, maxX = 10, minY = -10, maxY = 10, stepX = 1, stepY = 1;
	int x, y, scale = 40;  //比例尺为1：40
	int xi = -10, yi = -10;
	pDC->MoveTo(minX * scale - scale, 0);
	pDC->LineTo(maxX * scale + scale, 0);
	pDC->MoveTo(maxX * scale + scale - 10, 5);//绘制右箭头　
	pDC->LineTo(maxX * scale + scale, 0);
	pDC->LineTo(maxX * scale + scale - 10, -5);
	pDC->LineTo(maxX * scale + scale, 0);
	pDC->TextOut(maxX * scale + scale - 10, -10, CString("x"));
	pDC->MoveTo(0, minY * scale - scale);
	pDC->LineTo(0, maxY * scale + scale);
	pDC->MoveTo(-5, maxY * scale + scale - 10);//绘制上箭头
	pDC->LineTo(0, maxY * scale + scale);
	pDC->LineTo(5, maxY * scale + scale - 10);
	pDC->LineTo(0, maxY * scale + scale);
	pDC->TextOut(-15, maxY * scale + scale, CString("y"));

	//设置网格

	for (y = minY; y <= maxY; y += stepY)
	{
		//绘制横向网格线
		pDC->MoveTo(minY * scale, y * scale);
		pDC->LineTo(maxY * scale, y * scale);
		CString strValue;
		strValue.Format(_T("%d"), y);
		pDC->TextOut(-15, y * scale - 5, strValue);
	}
	for (x = minX; x <= maxX; x += stepX)
	{
		//绘制纵向网格线
		pDC->MoveTo(x * scale, minX * scale);
		pDC->LineTo(x * scale, maxX * scale);
		CString strValue;
		strValue.Format(_T("%d"), x);
		pDC->TextOut(x * scale - 15, -5, strValue);
	}
	pDC->MoveTo(500, -rect.bottom / 2);
	pDC->LineTo(500, rect.bottom / 2);
	pDC->TextOut(750, 400, CString("边表与桶表"));

	pDC->SelectObject(pOldPen);
	NewPen.DeleteObject();
}


// CmyProjectView 打印

BOOL CmyProjectView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CmyProjectView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CmyProjectView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}


// CmyProjectView 诊断

#ifdef _DEBUG
void CmyProjectView::AssertValid() const
{
	CView::AssertValid();
}

void CmyProjectView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CmyProjectDoc* CmyProjectView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CmyProjectDoc)));
	return (CmyProjectDoc*)m_pDocument;
}
#endif //_DEBUG


// CmyProjectView 消息处理程序


// 小组创建代码区开始##################################################
void CmyProjectView::makeBucketHead()
{
	ScanMax = pt_project[0].y;		// 记录全图最高y坐标
	ScanMin = pt_project[0].y;		// 记录全图最低y坐标
	CBucket* CurrentB{};
	if (ourAet)		// 若不是第一次运行该程序，则应当将链表清空；
	{
		delete[] ourAet;
		CurrentB = HeadB;
		HeadB = nullptr;
		CBucket* tmp{};
		while (CurrentB)
		{
			CurrentB = CurrentB->next;
			delete tmp;
		}
	}
	CAET* ourAet = new CAET[CtrlPNum];	// 记录所有边
	for (int i = 0; i < CtrlPNum; ++i)
	{
		if (pt_project[i].y > ScanMax) ScanMax = pt_project[i].y;	// 记录最高点
		if (pt_project[i].y < ScanMin) ScanMin = pt_project[i].y;	// 记录最低点
	}


	for (int i = ScanMin-1; i <= ScanMax; i++)	//建立桶结点
	{
		if (ScanMin-1 == i)						//桶头结点
		{
			HeadB = new CBucket;				//建立桶的头结点
			CurrentB = HeadB;					//CurrentB为CBucket当前结点指针
			CurrentB->ScanLine = ScanMin-1;
			CurrentB->p = NULL;					//没有连接边链表
			CurrentB->next = NULL;
		}
		else	//建立桶的其它结点
		{
			CurrentB->next = new CBucket;		//新建一个桶结点
			CurrentB = CurrentB->next;			//使CurrentB指向新建的桶结点
			CurrentB->ScanLine = i;
			CurrentB->p = NULL;					//没有连接边链表
			CurrentB->next = NULL;
		}
	}
	for (int i = 0, j = 0; j < CtrlPNum; ++i,++j)
	{
		ourAet[i].yMax = max(pt_project[j].y, pt_project[(j + 1) % CtrlPNum].y);	// 将最高点的y坐标存入边yMax变量中
		ourAet[i].x = pt_project[j].y < pt_project[(j + 1) % CtrlPNum].y ?			// 判断最低点是哪个
			pt_project[j].x : pt_project[(j + 1) % CtrlPNum].x;						// 将最低点的x坐标存入边x变量中
		double tmpY = pt_project[j].y - pt_project[(j + 1) % CtrlPNum].y;			// 记录x坐标差值，用来判断是否是水平的
		if (!tmpY)																	// 若是水平直线，则跳过该条直线，此时边表指针不动，点向后移动
		{
			--i;
			continue;
		}
		ourAet[i].k = (pt_project[j].x - pt_project[(j + 1) % CtrlPNum].x) / tmpY;	// 将k的倒数存入边的k变量中
		ourAet[i].next = nullptr;	//初始化next为空
		int CurrentY = min(pt_project[j].y, pt_project[(j + 1) % CtrlPNum].y);		// 将最低点的y坐标存入
		CurrentB = HeadB;
		while (CurrentB->ScanLine != CurrentY)
		{
			CurrentB = CurrentB->next;
		}

		CAET* pp = new CAET;
		pp->next = nullptr;
		pp->k = ourAet[i].k;
		pp->x = ourAet[i].x;
		pp->yMax = ourAet[i].yMax;
		insert(CurrentB, pp);
	}

	CurrentB = HeadB;

	scanline = ScanMin - 1;
	AET = HeadB;
	// printf("%d", HeadB->next->ScanLine);
	// delete [] ourAet;
}

// ###############################################
void CmyProjectView::OnHuitu()
{
	// TODO: 在此添加命令处理程序代码
	CDC* pDC = GetDC();

	CRect rect;
	GetClientRect(&rect);
	pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区:x轴水平向右，y轴垂直向上
	pDC->SetViewportOrg(rect.Width() / 2 - 400, rect.Height() / 2);//客户区中心为坐标系原点

	int i;
	if (flag == 1) {
		makeBucketHead();
		flag = 0;

		/*scanline = -2;
		tianchong(pDC);*/
	}
	else
	{
		make_aet();
		tianchong(pDC);
	}
	//画桶表
	struct CBucket* c1 = HeadB;
	CRect rect2(550, -430, 630, -400);
	for (c1 = HeadB->next; c1 != NULL; c1 = c1->next)
	{
		rect2.bottom += 30;
		rect2.top += 30;
		pDC->Rectangle(rect2);
		CString str;
		str.Format(_T("y=%d"), c1->ScanLine);
		pDC->TextOut(580, rect2.bottom - 10, str);
		//画边表
		struct CAET* a0 = c1->p;
		CRect rect3(650, rect2.top, 690, rect2.bottom);
		if (a0 != NULL)
		{//画从桶表到边表的箭头
			pDC->MoveTo(630, rect2.bottom - 15);
			pDC->LineTo(650, rect2.bottom - 15);
			pDC->LineTo(645, rect2.bottom - 10);
			pDC->LineTo(650, rect2.bottom - 15);
			pDC->LineTo(645, rect2.bottom - 20);
		}

		for (a0; a0 != NULL; a0 = a0->next)
		{
			int m;
			for (m = 0; m < 4; m++)
			{
				pDC->Rectangle(rect3);
				if (m == 0)
				{//x|ymin
					CString str2;
					str2.Format(_T("%.1lf"), a0->x);
					pDC->TextOut(rect3.left + 10, rect3.bottom - 10, str2);
				}
				if (m == 1)
				{//ymax
					CString str2;
					str2.Format(_T("%d"), a0->yMax);
					pDC->TextOut(rect3.left + 10, rect3.bottom - 10, str2);
				}
				if (m == 2)
				{//1/k
					CString str2;
					str2.Format(_T("%.2f"), a0->k);
					pDC->TextOut(rect3.left + 5, rect3.bottom - 10, str2);
				}
				if (m == 3)
				{
					if (a0->next != NULL)
					{//画连接边表的箭头
						pDC->MoveTo(rect3.CenterPoint().x, rect3.CenterPoint().y);
						pDC->LineTo(rect3.CenterPoint().x + 40, rect3.CenterPoint().y);
						pDC->LineTo(rect3.CenterPoint().x + 35, rect3.CenterPoint().y + 5);
						pDC->LineTo(rect3.CenterPoint().x + 40, rect3.CenterPoint().y);
						pDC->LineTo(rect3.CenterPoint().x + 35, rect3.CenterPoint().y - 5);
					}
					else
					{
						pDC->TextOut(rect3.left + 5, rect3.bottom - 10, CString("NULL"));
					}
				}
				if (m != 3)
				{
					rect3.right += 40;
					rect3.left += 40;
				}
				else
				{
					rect3.right += 60;
					rect3.left += 60;
				}

			}
		}
	}
}


// ######################################################################


void CmyProjectView::OnDuobianxing() //该函数绑定了菜单的按钮，为启动函数
{
	RedrawWindow();//清除当前画面
	pt = new CPoint[N_MAX_POINT];//存放实际显示点
	pt_project = new CPoint[N_MAX_POINT];//存放映射点
	m_flag = TRUE;//可以使用鼠标绘制控制点
	CtrlPNum = 0;//控制点初始个数为0
}

void CmyProjectView::OnLButtonDown(UINT nFlags, CPoint point)//获得屏幕控制点坐标 
{
	// TODO: Add your message handler code here and/or call default	
	if (m_flag)//m_flag为鼠标绘图的功能启用标志
	{
		pt[CtrlPNum] = point;
		CRect rect;
		GetClientRect(&rect);
		int x_project = (point.x - (rect.Width() / 2 - 400));
		int y_project = -(point.y - (rect.Height() / 2));

		if (x_project >= 0)
			x_project = (x_project + 20) / 40;
		else
			x_project = (x_project - 20) / 40;

		if (y_project >= 0)
			y_project = (y_project + 20) / 40;
		else
			y_project = (y_project - 20) / 40;

		pt[CtrlPNum].x = x_project * 40;		// 更改显示点
		pt[CtrlPNum].y = y_project * 40;
		CPoint p_t;
		p_t.x = x_project;
		p_t.y = y_project;
		pt_project[CtrlPNum] = p_t;

		CtrlPNum++;

		DrawCtrPolygon();

		if (CtrlPNum > 1 && x_project == pt_project[0].x && y_project == pt_project[0].y)//点击首点，则绘制结束
		{
			CtrlPNum--;
			flag = 1;
			m_flag = FALSE;
		}


	}
	CView::OnLButtonDown(nFlags, point);
}




void CmyProjectView::DrawCtrPolygon()//根据输入点绘制多边形
{
	CDC* pDC = GetDC();
	CRect rect;

	GetClientRect(&rect);
	pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区:x轴水平向右，y轴垂直向上
	pDC->SetViewportOrg(rect.Width() / 2 - 400, rect.Height() / 2);//客户区中心为坐标系原点

	CPen NewPen, * pOldPen;
	NewPen.CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
	pOldPen = pDC->SelectObject(&NewPen);
	CBrush NewBrush, * pOldBrush;
	NewBrush.CreateSolidBrush(RGB(0, 0, 0));
	pOldBrush = pDC->SelectObject(&NewBrush);
	for (int i = 0; i < CtrlPNum; i++)
	{
		if (0 == i)
		{
			pDC->MoveTo(pt[i].x, pt[i].y);
			pDC->Rectangle(pt[i].x - 2, pt[i].y - 2, pt[i].x + 2, pt[i].y + 2);
		}
		else
		{
			pDC->LineTo(pt[i].x, pt[i].y);
			pDC->Rectangle(pt[i].x - 2, pt[i].y - 2, pt[i].x + 2, pt[i].y + 2);
		}
	}
	pDC->SelectObject(pOldBrush);
	NewBrush.DeleteObject();
	pDC->SelectObject(pOldPen);
	NewPen.DeleteObject();
	ReleaseDC(pDC);
}

void CmyProjectView::OnRButtonDown(UINT nFlags, CPoint point)//结束函数
{
	//RedrawWindow();//清除多边形
	m_flag = FALSE;//结束鼠标绘图
	CView::OnRButtonDown(nFlags, point);
}



void CmyProjectView::OnMouseMove(UINT nFlags, CPoint point)//显示鼠标位置函数 
{
	// TODO: Add your message handler code here and/or call default
	CString strx, stry;//状态栏显示鼠标位置
	CMainFrame* pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;//要求包含MainFrm.h头文件
	CStatusBar* pStatus = &pFrame->m_wndStatusBar;//将m_wndStatusBar属性修改为公有
	if (pStatus)
	{
		strx.Format(CString("x=%d"), point.x);
		stry.Format(CString("y=%d"), point.y);
		CClientDC dc(this);
		CSize sizex = dc.GetTextExtent(strx);
		CSize sizey = dc.GetTextExtent(stry);
		// pStatus->SetPaneInfo(1, ID_INDICATOR_X, SBPS_NORMAL, sizex.cx);//改变状态栏
		pStatus->SetPaneText(1, strx);
		// pStatus->SetPaneInfo(2, ID_INDICATOR_Y, SBPS_NORMAL, sizey.cx);//改变状态栏
		pStatus->SetPaneText(2, stry);
	}
	CView::OnMouseMove(nFlags, point);
}


void CmyProjectView::make_aet()
{
	CBucket* CurrentB{ HeadB->next };
	CAET* CurrentAETC{ AET->p }, *CurrentC{ nullptr };
	if (scanline == ScanMax) return;
	++scanline;
	while (CurrentB->ScanLine != scanline)
	{
		CurrentB = CurrentB->next;
	}
	CurrentC = CurrentB->p;
	if(CurrentC)
	while (CurrentC->next)						// 指向未扫描的桶节点的最后一个边节点
	{
		CurrentC = CurrentC->next;
	}
	while (CurrentAETC)
	{
		if (CurrentAETC->yMax > scanline)
		{
			CAET* newCAET = new CAET;
			newCAET->k = CurrentAETC->k;					// k值复制
			newCAET->x = CurrentAETC->x + CurrentAETC->k;	// x值增加
			newCAET->yMax = CurrentAETC->yMax;				// yMax不变
			newCAET->next = nullptr;
			insert(CurrentB, newCAET);
		}
		CurrentAETC = CurrentAETC->next;					// 指向下一个
	}
	CurrentB = HeadB;
	while (CurrentB->ScanLine != scanline)
	{
		CurrentB = CurrentB->next;
	}
	AET = CurrentB;
}

void CmyProjectView::tianchong(CDC* pDC)
{
	CPen NewPen, * pOldPen;
	NewPen.CreatePen(PS_NULL, 0, RGB(0, 255, 0));
	pOldPen = pDC->SelectObject(&NewPen);
	CBrush NewBrush, * pOldBrush;
	NewBrush.CreateSolidBrush(RGB(0, 255, 0));
	pOldBrush = pDC->SelectObject(&NewBrush);

	CBucket* now;
	now = HeadB->next;
	while (now != NULL) {
		if (now->ScanLine == scanline) {
			break;
		}
		now = now->next;
	}
	CAET* p = now->p;
	CAET* q;
	int y = scanline;
	while (p != NULL) {
		q = p;
		p = p->next;
		for (int i = sheru(q->x); i < sheru(p->x); i++)
		{
			//CPoint points[4] = { CPoint(i*40+20,y*40+20),CPoint(i*40-20,y*40+20),CPoint(i*40-20,y*40-20),CPoint(i*40+20,y*40-20) };
			pDC->Ellipse(i * 40 - 20, y * 40 + 20, i * 40 + 20, y * 40 - 20);
		}
		p = p->next;
	}
	pDC->SelectObject(pOldBrush);
	NewBrush.DeleteObject();
	pDC->SelectObject(pOldPen);
	NewPen.DeleteObject();
}

int CmyProjectView::sheru(double x)
{
	if (x >= 0)
		x = x + 0.5;
	else
		x = x - 0.5;
	return ((int)x );
}

void CmyProjectView::insert(CBucket* CB, CAET* p)
{
	CAET* now = CB->p;
	if (now == NULL) {
		CB->p = p;
		return;
	}
	if (now->x > p->x) {
		p->next = now;
		CB->p = p;
		return;
	}
	while (now->next != NULL) {
		if (now->next->x > p->x) {
			break;
		}
		now = now->next;
	}
	p->next = now->next;
	now->next = p;
	return;
}
